package cn.xiuxius.embedded.command;

import cn.xiuxius.embedded.command.converter.ExistingFileConverter;
import cn.xiuxius.embedded.config.EasyYamlConfig;
import cn.xiuxius.embedded.keil.KeilProjectXML;
import cn.xiuxius.embedded.util.JarPathUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.xmlbeans.XmlException;
import picocli.CommandLine.*;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;
import java.util.concurrent.Callable;

@Command(
        name = "init",
        description = "Import existing uvopt project."
)
@Slf4j
public class InitCommand implements Callable<Integer> {

    @Parameters(index = "0", paramLabel = "<uvoptFile>", description = "The uvopt file to import.",
            converter = ExistingFileConverter.class)
    private File uvoptFile;

    @Parameters(index = "1", paramLabel = "<projectName>", description = "The name of the project.")
    private String projectName;

    @Option(names = {"-k", "--keil-install-path"}, paramLabel = "<keilInstallPath>", description = "The install path of Keil.")
    private Path keilInstallPath;

    @Option(names = {"-p", "--project-dir"}, paramLabel = "<projectDir>", description = "The directory of the project.")
    private Path pDir;


    @Override
    public Integer call() {
        try {
            String jarHome = JarPathUtil.getJarHome();
            if (jarHome == null) {
                log.error("Please set the environment variable EASY_STC_HOME to the path of the project.");
                return 1;
            }
            File templateDir = new File(Paths.get(jarHome, "template", "clion").toString());
            if (!templateDir.exists() || !templateDir.isDirectory()) {
                log.error("Template directory does not exist: {}", templateDir.getAbsolutePath());
                return 1;
            }

            // 3. 创建项目目录
            File projectDir;
            if (this.pDir == null) {
                projectDir = new File(projectName);
            } else {
                projectDir = this.pDir.toFile();
            }

            //判断目录下有没有文件

            if (projectDir.exists()) {
                File[] files = projectDir.listFiles();
                if (files != null && files.length > 0) {
                    log.error("The project directory is not empty.");
                    return 1;
                }
            }else {
                if (!projectDir.mkdirs()) {
                    log.error("Failed to create project directory: {}", projectDir.getAbsolutePath());
                    return 1;
                }
            }
            // 4. 拷贝模板目录全部内容到 projectDir
            FileUtils.copyDirectory(templateDir, projectDir);

            // 5. 拷贝 uvoptFile 到 projectDir/main 目录下
            File mainDir = new File(projectDir, "main");
            if (!mainDir.exists() && !mainDir.mkdirs()) {
                log.error("Failed to create main directory: {}", mainDir.getAbsolutePath());
                return 1;
            }
            File uvoptTargetFile = new File(mainDir, uvoptFile.getName());
            FileUtils.copyFile(uvoptFile, uvoptTargetFile);

            // 7. 初始化 ProjectConfig，uvoptFile相对路径为 main/uvoptFileName
            String uvoptRelativePath = Paths.get("main").resolve(uvoptFile.getName()).toString().replace("\\", "/");
            EasyYamlConfig easyYamlConfig = EasyYamlConfig.initSave(projectDir.getAbsolutePath(), projectName, uvoptRelativePath);
            if (easyYamlConfig == null) {
                log.error("Failed to initialize ProjectConfig");
                return 1;
            }

            // 8. 读取并更新 KeilProject 设置
            KeilProjectXML keilProjectXML = KeilProjectXML.loadUvproj(uvoptTargetFile.getAbsolutePath());
            EasyYamlConfig.KeilProject dkp = easyYamlConfig.getKeilProject();
            keilProjectXML.setCreateHexFile(dkp.getBuild().isGenHex());

            Path binPath = null;
            Path keilInstallPath = null;
            if (this.keilInstallPath != null) {
                keilInstallPath = this.keilInstallPath;
                //必须真实存在的文件夹
                if (!Files.isDirectory(keilInstallPath)) {
                    log.error("Invalid Keil install path: {}", keilInstallPath);
                    return 1;
                }
                binPath = keilInstallPath.resolve("C51").resolve("BIN");
                if (!Files.isDirectory(binPath)) {
                    log.error("Invalid Keil BIN path: {}", binPath.toAbsolutePath());
                    return 1;
                }
            }
            if (keilInstallPath == null || !Files.isDirectory(keilInstallPath)) {
                log.warn("Bin path not found or invalid.");
                Scanner scanner = new Scanner(System.in);
                System.out.print("Please enter the install path of Keil: ");
                String input = scanner.nextLine();
                keilInstallPath = Paths.get(input);
                if (!Files.isDirectory(keilInstallPath)) {
                    log.error("Invalid Keil install path: {}", keilInstallPath);
                    return 1;
                }
                binPath = keilInstallPath.resolve("C51").resolve("BIN");
                if (!Files.isDirectory(binPath)) {
                    log.error("Invalid Keil BIN path: {}", binPath.toAbsolutePath());
                    return 1;
                }
            }

            keilProjectXML.setBinPath(binPath);

            boolean keilUpdate = KeilProjectXML.updateUvproj(keilProjectXML, uvoptTargetFile.getAbsolutePath());

            if (!keilUpdate) {
                log.error("Failed to update uvproj file: {}", uvoptTargetFile.getAbsolutePath());
                return 1;
            }

            // 6. 读取并替换 projectDir/CMakeLists.txt 中的 ${projectName} 和 ${keil_include_dir}
            File cmakeFile = new File(projectDir, "CMakeLists.txt");
            if (!cmakeFile.exists()) {
                log.error("CMakeLists.txt does not exist in project directory.");
                return 1;
            }
            String cmakeContent = Files.readString(cmakeFile.toPath(), StandardCharsets.UTF_8);
            cmakeContent = cmakeContent.replace("${projectName}", projectName);

            // 直接用keilInstallPath，往下找C51/INC
            Path includePath = keilInstallPath.resolve("C51").resolve("INC");
            String includePathStr = includePath.toAbsolutePath().toString().replace("\\", "/");
            cmakeContent = cmakeContent.replace("${keil_include_dir}", includePathStr);
            Files.writeString(cmakeFile.toPath(), cmakeContent, StandardCharsets.UTF_8);
            log.info("Init project success.");
            return 0;
        } catch (IOException e) {
            log.error("Failed to initialize project", e);
        } catch (XmlException e) {
            log.error("Failed to parse uvopt file please check it: {}", uvoptFile.getAbsolutePath());
            return 1;
        }
        return 0;
    }


}
